package com.shengqin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shengqin.common.pojo.CommonPage;
import com.shengqin.config.CommonException;
import com.shengqin.entity.SummaryGraduation;
import com.shengqin.entity.SummaryResult;
import com.shengqin.entity.SummaryArchive;
import com.shengqin.mapper.SummaryArchiveMapper;
import com.shengqin.mapper.SummaryGraduationMapper;
import com.shengqin.pojo.summary.SummaryGraduationModel;
import com.shengqin.service.ISummaryArchiveService;
import com.shengqin.utils.GradeUtil;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SummaryArchiveServiceImpl extends ServiceImpl<SummaryArchiveMapper, SummaryArchive> implements ISummaryArchiveService {
    @Resource
    private SummaryArchiveMapper summaryArchiveMapper;
    @Resource
    private SummaryGraduationMapper summaryGraduationMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean summaryArchived(List<SummaryResult> summaryResultList, String schoolYear) {
        boolean result = true;
        if (CollectionUtil.isNotEmpty(summaryResultList)) {
            List<SummaryArchive> summaryArchiveList = Lists.newArrayList();
            summaryResultList.forEach(item -> {
                SummaryArchive summaryArchive = new SummaryArchive();
                BeanUtils.copyProperties(item, summaryArchive);
                summaryArchive.setSchoolYear(schoolYear);
                summaryArchiveList.add(summaryArchive);
            });
            saveOrUpdateBatch(summaryArchiveList);
        }
        return result;
    }

    @Override
    public Page<SummaryArchive> getPage(CommonPage<SummaryArchive> pageParam) {
        QueryWrapper<SummaryArchive> queryWrapper = new QueryWrapper<>();
        SummaryArchive summaryArchive = pageParam.getQueryParam();
        if (StrUtil.isNotEmpty(summaryArchive.getSchoolYear())) {
            queryWrapper.lambda().eq(SummaryArchive::getSchoolYear, summaryArchive.getSchoolYear());
        }
        if (StrUtil.isNotEmpty(summaryArchive.getStudyCode())) {
            queryWrapper.lambda().eq(SummaryArchive::getStudyCode, summaryArchive.getStudyCode());
        }
        if (StrUtil.isNotEmpty(summaryArchive.getName())) {
            queryWrapper.lambda().likeRight(SummaryArchive::getName, summaryArchive.getName());
        }
        queryWrapper.lambda().orderByDesc(SummaryArchive::getId);
        Page<SummaryArchive> testResultPage = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());
        page(testResultPage, queryWrapper);
        buildRecords(testResultPage.getRecords());
        return testResultPage;
    }

    private void buildRecords(List<SummaryArchive> records) {
        if(!CollectionUtil.isEmpty(records)){
            records.forEach(item -> {
                item.setGradeName(GradeUtil.getGradeName(item.getGradeId()));
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean calculateGraduation(String schoolYear) {
        if (StrUtil.isEmpty(schoolYear)) {
            throw new CommonException("学年信息不正确");
        }
        List<SummaryArchive> summaryArchiveList = summaryArchiveMapper.getTotalScore(Integer.valueOf(schoolYear));

        if(CollectionUtil.isEmpty(summaryArchiveList)){
            throw new CommonException("未查询到归档数据，请先进行成绩归档");
        }

        CompletableFuture.runAsync(() -> {
            QueryWrapper<SummaryGraduation> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(SummaryGraduation::getSchoolYear, schoolYear);
            summaryGraduationMapper.delete(queryWrapper);
            Map<String, List<SummaryArchive>> listMap = summaryArchiveList.stream().collect(Collectors.groupingBy(item -> item.getName() + item.getBirthday()));

            Flowable.fromIterable(listMap.values())
                    .parallel()
                    .runOn(Schedulers.io())
                    .flatMap(summaryArchives -> Flowable.fromCallable(() -> calculateSummaryArchives(summaryArchives,schoolYear)))
                    .sequential()
                    .blockingSubscribe(
                            item -> {},
                            error -> {
                                log.error("并行计算报错",error);
                                throw new CommonException("并行计算报错");
                                }, // 打印错误
                            () -> log.info("并行计算完成{}",listMap.size())
                    );
        });


        return true;
    }

    @Override
    public List<SummaryArchive> listByTempUniqKeys(Collection<String> tempKeys) {
        QueryWrapper<SummaryArchive> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(SummaryArchive::getTempUniqKey, tempKeys);
        return list(wrapper);
    }

    private SummaryGraduation calculateSummaryArchives(List<SummaryArchive> archiveList,String schoolYear){
        SummaryGraduation summaryGraduation = new SummaryGraduation();
        List<SummaryGraduationModel> listGraduationModels = Lists.newArrayList();
        archiveList.forEach(item -> {
            //历年体测数据
            SummaryGraduationModel summaryGraduationModel = new SummaryGraduationModel();
            summaryGraduationModel.setGrade(item.getGradeId());
            summaryGraduationModel.setScore(item.getTotalScore());
            summaryGraduationModel.setSchoolYear(item.getSchoolYear());
            summaryGraduationModel.setClassName(item.getClassesName());
            summaryGraduationModel.setPlanName(item.getPlanName());
            listGraduationModels.add(summaryGraduationModel);
            //基础数据
            summaryGraduation.setSchoolName(item.getSchoolName());
            summaryGraduation.setStudyCode(item.getStudyCode());
            summaryGraduation.setName(item.getName());
            summaryGraduation.setSex(item.getSex());
            summaryGraduation.setAddress(item.getAddress());
            summaryGraduation.setBirthday(item.getBirthday());
            summaryGraduation.setNation(item.getNation());
        });
        summaryGraduation.setTotalList(listGraduationModels);
        summaryGraduation.setSchoolYear(schoolYear);
        if (CollectionUtil.isNotEmpty(listGraduationModels)) {
            int graduationCount = listGraduationModels.size();
            if (graduationCount < 4) {
                summaryGraduation.setFlag(1);
            } else if (graduationCount == 4) {
                AtomicReference<BigDecimal> otherScore =new AtomicReference<>(BigDecimal.ZERO);
                AtomicReference<BigDecimal> lastScore = new AtomicReference<>(BigDecimal.ZERO);
                listGraduationModels.forEach(item -> {
                    if (item.getGrade() == 44) {
                        lastScore.set(item.getScore().multiply(BigDecimal.valueOf(0.5)));
                    } else {
                        otherScore.set(otherScore.get().add(item.getScore()));
                    }
                });
                summaryGraduation.setScore(lastScore.get().add(otherScore.get().divide(BigDecimal.valueOf(3),2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(0.5))));
                summaryGraduation.setFlag(0);
            } else {
                summaryGraduation.setFlag(2);
            }
            summaryGraduationMapper.insert(summaryGraduation);
        }
        return summaryGraduation;
    }
}
